#include "fgc.h"
#include <windows.h>

extern int yyparse();
extern void yyerror(char const *s, ...);
extern void reset_global();

extern int has_main;
extern int entry;
extern FILE *yyin;
extern int cnt_scan;

extern int row;
extern int column;

extern int include_stack_ptr;
extern func_table_t func_table;

extern vector <string> code_output;

char path[1000];
char file_input[100];
char file_output[100];

FILE *file_in;
FILE *file_out;

void error(char const *s, ...) {
	fflush(stderr);
    va_list ap;
    va_start(ap, s);
    fprintf(stderr, "error: ");
    vfprintf(stderr, s, ap);
    fprintf(stderr, "\n");
    exit(1);
}

void print_welcome() {
    printf("Functional Grapher Compiler v1.5.0 Final Release\n\n");
}

void print_help() {
    printf("fgc srcfile [option]\n\n");
    printf("\n");
    printf("  -o objfile          Specifies the object filename for output.\n");
    printf("                      If you use fgc without -o option, you will get an object file with extended name '.fgo'.\n");
    printf("\n");
    printf("  -h                  Show this information\n");
}

int main(int argc, char *argv[]) {    
    print_welcome();
    
	char buf[1000];
	DWORD dwResult;
	if (!(dwResult = GetModuleFileName(NULL, buf, 1000)))
        error("error: GetModuleFileName");
	if (!(dwResult = GetFullPathName(buf, 1000, path, NULL)))
        error("error: GetFullPathName");
	int ind = strlen(path) - 1;
	while (path[ind] != '\\') {
		if (ind > 0) ind--;
        else
            error("error while processing path");
    }
	path[ind + 1] = '\0';
	strcat(path, "include");
    
    int has_input = 0;
    int has_output = 0;

    for (int i = 1; i < argc; ++i) {
        if (argv[i][0] == '-') {
            switch (argv[i][1])	{
                case 'h':
                case 'H':
                case '?':
                    print_help();
                    return 0;
                case 'o':
                    has_output = 1;
                    strcpy(file_output, argv[i + 1]);
                    ++i;
                    break;
            }
        } else {
            has_input = 1;
            strcpy(file_input, argv[i]);
        }
    }

    if (!has_input)
        error("no input file");

    if (!has_output) {
        int has_extname = 0;
        int len = strlen(file_input);
        for (int i = len - 1; i >= 0 && !has_extname; --i) {
            if (file_input[i] == '.') {
                has_extname = 1;
                strncpy(file_output, file_input, i);
            }
        }
        if (!has_extname)
            strcpy(file_output, file_input);
        strcat(file_output, ".fgo");
    }

    file_in = fopen(file_input, "r");

    if (!file_in)
        error("can't open input file '%s'", file_input);
    
    file_out = fopen(file_output, "w");

    if (!file_out)
        error("can't create output file '%s'", file_output);

    yyin = file_in;

    int ret = yyparse(); //first time
    if (ret != 0)
        error("fatal error, parse aborted");
    code_output.clear();

    //second time
    include_stack_ptr = 0;
    row = column = 0;
    ++cnt_scan;
    reset_global();
    fclose(file_in);
    file_in = fopen(file_input, "r");
    yyin = file_in;

    ret = yyparse(); 
    if (ret != 0)
        error("fatal error, parse aborted");
    if (!has_main)
        error("missing defenition of function 'main'");
    if (entry < 0)
        error("no entry for function 'main'");

    for (func_table_t::iterator it = func_table.begin(); it != func_table.end(); ++it) {
        if (it->second.defined == 0 && it->second.is_system == 0)
            error("can't find definition of non-system function '%s'", it->first.c_str());
    }
    printf("Source '%s' compiled\n", file_input);

    fprintf(file_out, "call !%d\n", entry);
    for (int i = 0; i < (int)code_output.size(); ++i) {
        fprintf(file_out, "%s\n", code_output[i].c_str());
    }
    fclose(file_in);
    fclose(file_out);

    printf("Object '%s' generated\n", file_output);
    return 0;
}
